# -*- coding: utf-8 -*-
# @Project : gate-v541-auto-test
# @File    : v541Public.py
# @Author  : 朱宽
# @Time    : 2021/8/12 10:25
# @Software: Win10 / Python3 / Pycharm
from config.globalConfig import test_data_path
from config import globalConfig
from src.utils import HandleString , ByteByByteXOR
import json
import os

class v541Public():
    '''
        这个类主要实现该框架内的业务公共处理方法
    '''

    def v541_authentication(self,tcp_class,client,file_name):
        __name = file_name.split('.')
        __file_name = __name[0] + '.json'
        __json_path = test_data_path + __file_name  # 组合保存为json格式数据的文件路径

        __tcp_class = tcp_class
        __client = client

        send_data=None
        with open(__json_path) as f:
            data_all=json.load(f)
        data_all_list=data_all
        for i in data_all_list:
            if i['TestCaseFlag'] == 'authentication0102' and i['CorrectFlag']==True:
                send_data=i['SendData']
                break #只取第一个正确的数据

        replace_send_data_AKey=self.replace_AKey(hex_str=send_data,file_name=__file_name)
        __tcp_class.send(client=__client,data=replace_send_data_AKey)
        print('固定鉴权包为：',replace_send_data_AKey)
        res=__tcp_class.receive(client=__client,eol='7e')
        print('固定鉴权包回复包为：',res)

    def v541_hb(self,tcp_class,client,file_name):
        __name = file_name.split('.')
        __file_name = __name[0] + '.json'
        __json_path = test_data_path + __file_name  # 组合保存为json格式数据的文件路径

        __tcp_class = tcp_class
        __client = client

        send_data=None
        with open(__json_path) as f:
            data_all=json.load(f)
        data_all_list=data_all
        for i in data_all_list:
            if i['TestCaseFlag'] == 'hb0002' and i['CorrectFlag']==True:
                send_data=i['SendData']
                break #只取第一个正确的数据

        __tcp_class.send(client=__client,data=send_data)
        print('固定心跳包为：',send_data)
        res=__tcp_class.receive(client=__client,eol='7e')
        print('固定心跳包回复包为：',res)


    def output_hex_packet_7e(self, data_list):
        '''
        拼接数据字段，计算校验位，加上首尾标识符，并转义
        :param data_list: ["11","01","0000111122223333","7000","3201","0001"]
        :return:
        '''
        # print(data_list,type(data_list))
        if data_list != None:
            if type(data_list) == list:
                hex_str = (''.join(data_list)).lower()  # 将消息头和消息体拼接在一起，形成16进制数的字符串
                #print('拼接后的字符串为：', hex_str)

                Handle_String = HandleString.HandleString()  # 初始化这个类，操作字符串
                list_hex = Handle_String.list_hex_string(hex_string=hex_str)  # 将16进制字符串转换为字节列表
                #print('按字节转换为列表：', list_hex)

                crc_class = ByteByByteXOR.ByteXOR()
                crc_byte = crc_class.byte_by_byte_xor(pData=list_hex)  # 计算校验位
                #print('计算后的校验位为：', crc_byte, type(crc_byte))

                tem = (hex_str + crc_byte).lower()  # 将 消息头、消息体、校验码 的16进制数字符串进行拼接；为转义“0x7e”做准备
                if (int(len(tem) % 2)) == 0:
                    tem_list = list(tem)
                    tem_double_list = []
                    for i in range(0, len(tem_list), 2):
                        ''' 这个for循环主要实现每两个16进制数 '''
                        n = tem_list[i] + tem_list[i + 1]
                        tem_double_list.append(n)
                    tem_double_list_str = str(tem_double_list)  # 将列表的所有内容转换为字符串，包括"[]"
                    tem_double_list_str = tem_double_list_str.replace('7d', '7d01')  # 将 7d 转义成 7d01 ，必须先转义7d，才能转义7e
                    tem_double_list_str = tem_double_list_str.replace('7e', '7d02') # 将 7e 转义成 7d02
                    tem_double_list=eval(tem_double_list_str) # 将列表形式的字符串转换为列表
                    #print('替换后的字节列表：',tem_double_list)
                else:
                    tem_double_list = []
                    print('输入数据的位数错误！每个字节用两个16进制数或两个10进制数表示。')

                result = '7e'+''.join(tem_double_list)+'7e'
            else:
                result = data_list
                print('CombinePacket.py:不支持 SendData 或 ResponseData 的数据类型进行转换！')
        else:
            result = None

        if result!=None:
            return result.lower()
        else:
            return result

    def unescape(self, hex_str):
        '''
        这个方法主要实现 16进制字符串的反转义功能；
        （1）将 7d01 转义成 7d
        （2）将 7d02 转义成 7e
        :param hex_str: 应答包
        :return:将消息头、消息体、校验码中的特定组合转义之后，加上标志位，方便后续封装的方法进行处理
        '''
        tem = hex_str[2:-2].lower()  # 取字符串 第2位 与 倒数第2位 之间的数据；不包括 第2位 和 倒数第2位
        # print(tem)

        if (int(len(tem) % 2)) == 0:

            tem_list = list(tem)
            tem_double_list = []

            for i in range(0, len(tem_list), 2):
                ''' 这个for循环主要实现每两个16进制数 '''
                n = tem_list[i] + tem_list[i + 1]
                tem_double_list.append(n)

            tem_double_list_str = str(tem_double_list)  # 将列表的所有内容转换为字符串，包括"[]"
            tem_double_list_str = tem_double_list_str.replace("'7d', '01'", "'7d'")  # 将 7d 转义成 7d01
            tem_double_list_str = tem_double_list_str.replace("'7d', '02'", "'7e'")  # 将 7e 转义成 7d02
            tem_double_list = eval(tem_double_list_str)  # 将列表形式的字符串转换为列表

            # 将消息头、消息体、校验码中的特定组合转义之后，加上标志位，方便后续封装的方法进行处理
            result = hex_str[0:2] + ''.join(tem_double_list) + hex_str[-2:]
            # 添加传入的字符串的 前两位 和 后两位；hex_str[-2:]表示：获取倒数第二位到结尾，包括倒数第二位

            return result

        else:
            print('输入数据的位数错误！每个字节用两个16进制数或两个10进制数表示。')
            return hex_str  # 输入的数据不符合字节数据长度时，直接返回输入值

    def get_AKey(self,hex_str,file_name):
        '''
        这个方法主要是抽取注册应答包中的 鉴权码，并将 鉴权码 存入json文件中
        :param hex_str:
        :return:
        '''
        if str(hex_str) != 'timed out':
            res_unescape = self.unescape(hex_str=hex_str)  # 反转义
            #print(res_unescape)
            body_property=res_unescape[6:10] #取消息体属性字段
            #print(body_property)
            tem=int(body_property,base=16) #使用int函数将16进制数的字符串转换为int型数据
            #print(tem,type(tem))
            tem=bin(tem)[2:].zfill(16) # 左边是高位，右边是低位；去掉0b，剩余补齐16位；bin()函数返回的是字符串型数据
            #print(tem,type(tem))
            tem_13=tem[-14]#取二进制数中的第13位的至（0开始）
            if tem_13=='0':
                a_key=hex_str[32:-4] #不含消息包封装项
            else:
                a_key=hex_str[40:-4] #含消息包封装项

            #print(len(a_key),a_key)

            #将鉴权码存入json文件中
            file_name_half=file_name.split('.')[0]
            with open(globalConfig.test_data_path + file_name_half + '-AKey' + '.json', 'w+') as f:
                json.dump(a_key, f, indent=4, ensure_ascii=False)

            return a_key

        else:
            print('输入值为：',str(hex_str),' ！ 没有鉴权码！')
            return None

    def replace_AKey(self,hex_str,file_name):
        '''
        这个方法是为了替换鉴权包中的鉴权码部分
        :param hex_str: 鉴权数据包
        :param file_name:测试数据文件名称；'xxx.xlsx'
        :return:
        '''
        tem_list=[]

        file_name_half = file_name.split('.')[0]
        with open(globalConfig.test_data_path + file_name_half + '-AKey' + '.json') as f:
            a_key = json.load(f)

        mes_id=hex_str[2:6]
        mes_body_attribute=hex(int(len(a_key)/2))[2:].zfill(4) #16进制字符串显示，补齐4位
        cell_phone=hex_str[10:22]
        mes_number=hex_str[22:26]

        tem_list.append(mes_id)
        tem_list.append(mes_body_attribute)
        tem_list.append(cell_phone)
        tem_list.append(mes_number)
        tem_list.append(a_key)

        result=self.output_hex_packet_7e(data_list=tem_list)
        return result

    def remove_AKey(self,file_name):
        file_name_half = file_name.split('.')[0]
        file_AKey_path= globalConfig.test_data_path + file_name_half + '-AKey' + '.json'
        if os.path.exists(file_AKey_path):
            os.remove(file_AKey_path)
            print('\n已经移除AKey文件！')
        else:
            print('\n不存在AKey的文件！')



if __name__ == "__main__":
    test = v541Public()
    hex_str = '7e8100000f0139666699990000000000303133393636363639393939bd7e'
    file_name='zk-test-data.xlsx'
    test.get_AKey(hex_str,file_name)

